home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / nt / source.exe / POSIX / TERM / TERMCAP.C < prev    next >
C/C++ Source or Header  |  1993-06-08  |  12KB  |  463 lines

  1. /*
  2.  * Copyright (c) 1980 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #ifndef lint
  35. static char sccsid[] = "@(#)termcap.c    5.5 (Berkeley) 6/1/90";
  36. #endif /* not lint */
  37.  
  38. #define    BUFSIZ        1024
  39. #define MAXHOP        32    /* max number of tc= indirections */
  40. #define    PBUFSIZ        512    /* max length of filename path */
  41. #define    PVECSIZ        32    /* max number of names in path */
  42.  
  43. #if 0
  44. #include <stdio.h>
  45. #endif
  46.  
  47. #include <ctype.h>
  48. #include "pathnames.h"
  49.  
  50. //#include <debug.h>
  51. //#include "debugflg.h"
  52. //long DbgFlg = (TGETENT);
  53. #define DBGP(FLG, FMT)
  54.  
  55. /*
  56.  * termcap - routines for dealing with the terminal capability data base
  57.  *
  58.  * BUG:        Should use a "last" pointer in tbuf, so that searching
  59.  *        for capabilities alphabetically would not be a n**2/2
  60.  *        process when large numbers of capabilities are given.
  61.  * Note:    If we add a last pointer now we will screw up the
  62.  *        tc capability. We really should compile termcap.
  63.  *
  64.  * Essentially all the work here is scanning and decoding escapes
  65.  * in string capabilities.  We don't use stdio because the editor
  66.  * doesn't, and because living w/o it is not hard.
  67.  */
  68.  
  69. static    char *tbuf;
  70. static    int hopcount;    /* detect infinite loops in termcap, init 0 */
  71. static    char pathbuf[PBUFSIZ];        /* holds raw path of filenames */
  72. static    char *pathvec[PVECSIZ];        /* to point to names in pathbuf */
  73. static    char **pvec;            /* holds usable tail of path vector */
  74. char    *tskip();
  75. char    *tgetstr();
  76. char    *tdecode();
  77. char    *getenv();
  78.  
  79. /*
  80.  * Get an entry for terminal name in buffer bp from the termcap file.
  81.  */
  82. tgetent(bp, name)
  83.     char *bp, *name;
  84. {
  85.     register char *p;
  86.     register char *cp;
  87.     register int c;
  88.     char *term, *home, *termpath;
  89.     char **fname = pathvec;
  90.  
  91.     pvec = pathvec;
  92.     tbuf = bp;
  93.     p = pathbuf;
  94.     cp = getenv("TERMCAP");
  95. DBGP(TGETENT, ("tgetent: TERMCAP=>%s<\n", cp));
  96.     /*
  97.      * TERMCAP can have one of two things in it. It can be the
  98.      * name of a file to use instead of /etc/termcap. In this
  99.      * case it better start with a "/". Or it can be an entry to
  100.      * use so we don't have to read the file. In this case it
  101.      * has to already have the newlines crunched out.  If TERMCAP
  102.      * does not hold a file name then a path of names is searched
  103.      * instead.  The path is found in the TERMPATH variable, or
  104.      * becomes "$HOME/.termcap /etc/termcap" if no TERMPATH exists.
  105.      */
  106.     if (!cp || *cp != '/') {    /* no TERMCAP or it holds an entry */
  107.         if (termpath = getenv("TERMPATH"))
  108.             strncpy(pathbuf, termpath, PBUFSIZ);
  109.         else {
  110.             if (home = getenv("HOME")) {    /* set up default */
  111.                 p += strlen(home);    /* path, looking in */
  112.                 strcpy(pathbuf, home);    /* $HOME first */
  113.                 *p++ = '/';
  114.             }    /* if no $HOME look in current directory */
  115.             strncpy(p, _PATH_DEF, PBUFSIZ - (p - pathbuf));
  116.         }
  117. DBGP(TGETENT, ("tgetent: pathbuf=>%s<\n", pathbuf));
  118.     }
  119.     else                /* user-defined name in TERMCAP */
  120.         strncpy(pathbuf, cp, PBUFSIZ);    /* still can be tokenized */
  121.  
  122.     *fname++ = pathbuf;    /* tokenize path into vector of names */
  123.     while (*++p)
  124.         if (*p == ' ' || *p == ':') {
  125.             *p = '\0';
  126.             while (*++p)
  127.                 if (*p != ' ' && *p != ':')
  128.                     break;
  129.             if (*p == '\0')
  130.                 break;
  131.             *fname++ = p;
  132.             if (fname >= pathvec + PVECSIZ) {
  133.                 fname--;
  134.                 break;
  135.             }
  136.         }
  137.     *fname = (char *) 0;            /* mark end of vector */
  138.     if (cp && *cp && *cp != '/') {
  139.         tbuf = cp;
  140.         c = tnamatch(name);
  141.         tbuf = bp;
  142.         if (c) {
  143.             strcpy(bp,cp);
  144. DBGP(TGETENT, ("tgetent: returned at tnchktc\n"));
  145.             return (tnchktc());
  146.         }
  147.     }
  148. DBGP(TGETENT, ("tgetent: returned at tfindent\n"));
  149.     return (tfindent(bp, name));    /* find terminal entry in path */
  150. }
  151.  
  152. /*
  153.  * tfindent - reads through the list of files in pathvec as if they were one
  154.  * continuous file searching for terminal entries along the way.  It will
  155.  * participate in indirect recursion if the call to tnchktc() finds a tc=
  156.  * field, which is only searched for in the current file and files ocurring
  157.  * after it in pathvec.  The usable part of this vector is kept in the global
  158.  * variable pvec.  Terminal entries may not be broken across files.  Parse is
  159.  * very rudimentary; we just notice escaped newlines.
  160.  */
  161. tfindent(bp, name)
  162.     char *bp, *name;
  163. {
  164.     register char *cp;
  165.     register int c;
  166.     register int i, cnt;
  167.     char ibuf[BUFSIZ];
  168.     int opencnt = 0;
  169.     int tf;
  170.  
  171.     tbuf = bp;
  172. nextfile:
  173.     i = cnt = 0;
  174.     while (*pvec && (tf = open(*pvec, 0)) < 0)
  175.         pvec++;
  176.     if (!*pvec)
  177.         return (opencnt ? 0 : -1);
  178.     opencnt++;
  179.     for (;;) {
  180.         cp = bp;
  181.         for (;;) {
  182.             if (i == cnt) {
  183.                 cnt = read(tf, ibuf, BUFSIZ);
  184.                 if (cnt <= 0) {
  185.                     close(tf);
  186.                     pvec++;
  187.                     goto nextfile;
  188.                 }
  189.                 i = 0;
  190.             }
  191.             c = ibuf[i++];
  192. #if WIN_NT
  193.             if ( c == '\r' )
  194.                 c = ibuf[i++];
  195. #endif
  196.             if (c == '\n') {
  197.                 if (cp > bp && cp[-1] == '\\'){
  198.                     cp--;
  199.                     continue;
  200.                 }
  201.                 break;
  202.             }
  203.             if (cp >= bp+BUFSIZ) {
  204.                 write(2,"Termcap entry too long\n", 23);
  205.                 break;
  206.             } else
  207.                 *cp++ = c;
  208.         }
  209.         *cp = 0;
  210.  
  211.         /*
  212.          * The real work for the match.
  213.          */
  214.         if (tnamatch(name)) {
  215.             close(tf);
  216.             return(tnchktc());
  217.         }
  218.     }
  219. }
  220.  
  221. /*
  222.  * tnchktc: check the last entry, see if it's tc=xxx. If so,
  223.  * recursively find xxx and append that entry (minus the names)
  224.  * to take the place of the tc=xxx entry. This allows termcap
  225.  * entries to say "like an HP2621 but doesn't turn on the labels".
  226.  * Note that this works because of the left to right scan.
  227.  */
  228. tnchktc()
  229. {
  230.     register char *p, *q;
  231.     char tcname[16];    /* name of similar terminal */
  232.     char tcbuf[BUFSIZ];
  233.     char *holdtbuf = tbuf;
  234.     int l;
  235.  
  236.     p = tbuf + strlen(tbuf) - 2;    /* before the last colon */
  237.     while (*--p != ':')
  238.         if (p<tbuf) {
  239.             write(2, "Bad termcap entry\n", 18);
  240.             return (0);
  241.         }
  242.     p++;
  243.     /* p now points to beginning of last field */
  244.     if (p[0] != 't' || p[1] != 'c')
  245.         return(1);
  246.     strcpy(tcname,p+3);
  247.     q = tcname;
  248.     while (*q && *q != ':')
  249.         q++;
  250.     *q = 0;
  251.     if (++hopcount > MAXHOP) {
  252.         write(2, "Infinite tc= loop\n", 18);
  253.         return (0);
  254.     }
  255.     if (tfindent(tcbuf, tcname) != 1) {
  256.         hopcount = 0;        /* unwind recursion */
  257.         return(0);
  258.     }
  259.     for (q=tcbuf; *q != ':'; q++)
  260.         ;
  261.     l = p - holdtbuf + strlen(q);
  262.     if (l > BUFSIZ) {
  263.         write(2, "Termcap entry too long\n", 23);
  264.         q[BUFSIZ - (p-tbuf)] = 0;
  265.     }
  266.     strcpy(p, q+1);
  267.     tbuf = holdtbuf;
  268.     hopcount = 0;            /* unwind recursion */
  269.     return(1);
  270. }
  271.  
  272. /*
  273.  * Tnamatch deals with name matching.  The first field of the termcap
  274.  * entry is a sequence of names separated by |'s, so we compare
  275.  * against each such name.  The normal : terminator after the last
  276.  * name (before the first field) stops us.
  277.  */
  278. tnamatch(np)
  279.     char *np;
  280. {
  281.     register char *Np, *Bp;
  282.  
  283.     Bp = tbuf;
  284.     if (*Bp == '#')
  285.         return(0);
  286.     for (;;) {
  287.         for (Np = np; *Np && *Bp == *Np; Bp++, Np++)
  288.             continue;
  289.         if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0))
  290.             return (1);
  291.         while (*Bp && *Bp != ':' && *Bp != '|')
  292.             Bp++;
  293.         if (*Bp == 0 || *Bp == ':')
  294.             return (0);
  295.         Bp++;
  296.     }
  297. }
  298.  
  299. /*
  300.  * Skip to the next field.  Notice that this is very dumb, not
  301.  * knowing about \: escapes or any such.  If necessary, :'s can be put
  302.  * into the termcap file in octal.
  303.  */
  304. static char *
  305. tskip(bp)
  306.     register char *bp;
  307. {
  308.  
  309.     while (*bp && *bp != ':')
  310.         bp++;
  311.     if (*bp == ':')
  312.         bp++;
  313.     return (bp);
  314. }
  315.  
  316. /*
  317.  * Return the (numeric) option id.
  318.  * Numeric options look like
  319.  *    li#80
  320.  * i.e. the option string is separated from the numeric value by
  321.  * a # character.  If the option is not found we return -1.
  322.  * Note that we handle octal numbers beginning with 0.
  323.  */
  324. tgetnum(id)
  325.     char *id;
  326. {
  327.     register int i, base;
  328.     register char *bp = tbuf;
  329.  
  330.     for (;;) {
  331.         bp = tskip(bp);
  332.         if (*bp == 0)
  333.             return (-1);
  334.         if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
  335.             continue;
  336.         if (*bp == '@')
  337.             return(-1);
  338.         if (*bp != '#')
  339.             continue;
  340.         bp++;
  341.         base = 10;
  342.         if (*bp == '0')
  343.             base = 8;
  344.         i = 0;
  345.         while (isdigit(*bp))
  346.             i *= base, i += *bp++ - '0';
  347.         return (i);
  348.     }
  349. }
  350.  
  351. /*
  352.  * Handle a flag option.
  353.  * Flag options are given "naked", i.e. followed by a : or the end
  354.  * of the buffer.  Return 1 if we find the option, or 0 if it is
  355.  * not given.
  356.  */
  357. tgetflag(id)
  358.     char *id;
  359. {
  360.     register char *bp = tbuf;
  361.  
  362.     for (;;) {
  363.         bp = tskip(bp);
  364.         if (!*bp)
  365.             return (0);
  366.         if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1]) {
  367.             if (!*bp || *bp == ':')
  368.                 return (1);
  369.             else if (*bp == '@')
  370.                 return(0);
  371.         }
  372.     }
  373. }
  374.  
  375. /*
  376.  * Get a string valued option.
  377.  * These are given as
  378.  *    cl=^Z
  379.  * Much decoding is done on the strings, and the strings are
  380.  * placed in area, which is a ref parameter which is updated.
  381.  * No checking on area overflow.
  382.  */
  383. char *
  384. tgetstr(id, area)
  385.     char *id, **area;
  386. {
  387.     register char *bp = tbuf;
  388.  
  389.     for (;;) {
  390.         bp = tskip(bp);
  391. #if 0
  392.     printf("%p=bp\n",bp);
  393.     if ( bp != NULL )
  394.         printf("%02x=*bp\n",*bp);
  395. #endif
  396.         if (!*bp)
  397.             return (0);
  398.         if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
  399.             continue;
  400. #if 0
  401.     printf("%c=*bp\n",*bp);
  402. #endif
  403.         if (*bp == '@')
  404.             return(0);
  405.         if (*bp != '=')
  406.             continue;
  407.         bp++;
  408. #if 0
  409.     printf("%s=bp\n",bp);
  410. #endif
  411.         return (tdecode(bp, area));
  412.     }
  413. }
  414.  
  415. /*
  416.  * Tdecode does the grung work to decode the
  417.  * string capability escapes.
  418.  */
  419. static char *
  420. tdecode(str, area)
  421.     register char *str;
  422.     char **area;
  423. {
  424.     register char *cp;
  425.     register int c;
  426.     register char *dp;
  427.     int i;
  428.  
  429.     cp = *area;
  430.     while ((c = *str++) && c != ':') {
  431.         switch (c) {
  432.  
  433.         case '^':
  434.             c = *str++ & 037;
  435.             break;
  436.  
  437.         case '\\':
  438.             dp = "E\033^^\\\\::n\nr\rt\tb\bf\f";
  439.             c = *str++;
  440. nextc:
  441.             if (*dp++ == c) {
  442.                 c = *dp++;
  443.                 break;
  444.             }
  445.             dp++;
  446.             if (*dp)
  447.                 goto nextc;
  448.             if (isdigit(c)) {
  449.                 c -= '0', i = 2;
  450.                 do
  451.                     c <<= 3, c |= *str++ - '0';
  452.                 while (--i && isdigit(*str));
  453.             }
  454.             break;
  455.         }
  456.         *cp++ = c;
  457.     }
  458.     *cp++ = 0;
  459.     str = *area;
  460.     *area = cp;
  461.     return (str);
  462. }
  463.